#Copyright (c) 2012-8 Civa Lin. All rights reserved.
"""
File Utility 檔案工具模組

本模組提供檔案的尋找、創建、存取、刪除等工具，是官方 os 相關功能的擴充。
"""

import os
import os.path
import sys
import itertools
import subprocess

def userdir():
    '''取得當前的使用者資料夾'''
    # 環境變數 HOME 用在 Linux 系統，USERPROFILE 用在 Windows 系統
    return os.getenv('HOME') or os.getenv('USERPROFILE')

def which(program):
    '''測試指定的程式是否存在，如果存在，回傳完整程式路徑

        範例：
            >>> which('hg')

        program - 可以是完整路徑，也可以只含檔名。
                  只含檔名時，會去系統 PATH 列表中尋找實際位置。

        return ==> 指定程式不存在回傳 None，否則回傳完整程式路徑。
        '''
    def is_exe(filename):
        return os.path.isfile(filename) and os.access(filename, os.X_OK)
    dirname = os.path.dirname(program)
    if dirname: # 如果執行檔前面存在路徑，將輸入的 program 當成絕對路徑來測試
        if is_exe(program):
            return program
    else: # 如果執行檔前面沒有路徑，則從 PATH 中讀取可能路徑，依序確認
        for path in os.environ['PATH'].split(os.pathsep):
            exe_filename = os.path.join(path, program) # 完整測試路徑
            if is_exe(exe_filename):
                return exe_filename
            # windows下的執行檔 x 通常以 .exe 結尾。
            # 所以若當前平台為 windows，則還要追加測試……
            elif sys.platform.startswith('win'): # windows
                if is_exe(exe_filename + '.exe'):
                    return exe_filename + '.exe' # 回傳 x.exe 的路徑
    return None # 全部測試不過，回傳 None

def openby(*files, opener = ''):
    '''用外部程式打開指定檔案。

        如果 opener 沒指定，則使用系統預設程式來打開程式。

        opener = 用來開啟檔案的外部程式。可以是 xdg-open 之類的中介程式，
                 也可以是 vim 一類的目的程式。

        在所有平台下都能運作。
        '''
    # 尋找執行器
    if opener:
        prog = which(opener)
    else:
        if sys.platform.startswith('win'):
            # window 的啟動方式和其他人不一樣
            for f in files:
                os.startfile(f)
            return
        elif sys.platform.startswith('linux'):
            prog = which('xdg-open')
        elif sys.platform.startswith('darwin'):
            prog = 'open'
        else:
            raise RuntimeError('Platform not support!')
    for f in files:
        subprocess.call((prog, f))

# 發現官方 os.makedirs() 就是在做這個的功能，故註解掉。
# def mkdir(dir):
#     '''如同 os.mkdir() 一樣建立目錄。
# 
#         但會遞迴建立路徑上所有未建立的目錄，而不會因為父目錄不存在而失敗。
#         '''
#     if os.path.isdir(dir): return
#     else:
#         mkdir(os.path.dirname(dir))
#         os.mkdir(dir)
